#include "stdafx.h"
#include "QMemFile.h"

QMemFile::QMemFile( UINT nGrowBytes /*= 1024*/ )

{
	Q_ASSERT(nGrowBytes <= UINT_MAX);

	m_nGrowBytes = nGrowBytes;
	m_nPosition = 0;
	m_nBufferSize = 0;
	m_nFileSize = 0;
	m_lpBuffer = NULL;
	m_bAutoDelete = TRUE;
}

QMemFile::QMemFile( BYTE* lpBuffer,UINT nBufferSize,UINT nGrowBytes /*= 0*/ )
{
	if (lpBuffer == NULL && nBufferSize != 0) 
	{
		Q_ASSERT(0);
	}

	Q_ASSERT(nGrowBytes <= UINT_MAX);

	m_nGrowBytes = nGrowBytes;
	m_nPosition = 0;
	m_nBufferSize = nBufferSize;
	m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0;
	m_lpBuffer = lpBuffer;
	m_bAutoDelete = FALSE;
}

QMemFile::~QMemFile()
{
	if (m_lpBuffer)
		close();
	Q_ASSERT(m_lpBuffer == NULL);

	m_nGrowBytes = 0;
	m_nPosition = 0;
	m_nBufferSize = 0;
	m_nFileSize = 0;
}

void QMemFile::attach( BYTE* lpBuffer,UINT nBufferSize, UINT nGrowBytes /*= 0*/ )
{
	if (lpBuffer == NULL && nBufferSize != 0) 
	{
		Q_ASSERT(0);
	}

	Q_ASSERT(m_lpBuffer == NULL);

	m_nGrowBytes = nGrowBytes;
	m_nPosition = 0;
	m_nBufferSize = nBufferSize;
	m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0;
	m_lpBuffer = lpBuffer;
	m_bAutoDelete = FALSE;
}

BYTE* QMemFile::detach()
{
	BYTE* lpBuffer = m_lpBuffer;
	m_lpBuffer = NULL;
	m_nFileSize = 0;
	m_nBufferSize = 0;
	m_nPosition = 0;

	return lpBuffer;
}

BYTE* QMemFile::alloc( int nBytes )
{
	return (BYTE*)malloc(nBytes);
}

BYTE* QMemFile::realloc( BYTE* lpMem, int nBytes )
{
	Q_ASSERT(nBytes > 0);	// nBytes == 0 means free		
	return (BYTE*)realloc(lpMem, nBytes);
}

BYTE* QMemFile::memcpy( BYTE* lpMemTarget, const BYTE* lpMemSource, int nBytes )
{
	Q_ASSERT(lpMemTarget != NULL);
	Q_ASSERT(lpMemSource != NULL);
	memcpy_s(lpMemTarget, nBytes, lpMemSource, nBytes);
	return lpMemTarget;
}

void QMemFile::freeMem( BYTE* lpMem )
{
	Q_ASSERT(lpMem != NULL);

	free(lpMem);
}

void QMemFile::growfile( int dwNewLen )
{
	if (dwNewLen > m_nBufferSize)
	{
		// grow the buffer
		int dwNewBufferSize = m_nBufferSize;

		// watch out for buffers which cannot be grown!
		Q_ASSERT(m_nGrowBytes != 0);
		if (m_nGrowBytes == 0)
			Q_ASSERT(0);

		// determine new buffer size
		while (dwNewBufferSize < dwNewLen)
			dwNewBufferSize += m_nGrowBytes;

		// allocate new buffer
		BYTE* lpNew;
		if (m_lpBuffer == NULL)
			lpNew = alloc(dwNewBufferSize);
		else
			lpNew = realloc(m_lpBuffer, dwNewBufferSize);

		if (lpNew == NULL)
			Q_ASSERT(0);


		m_lpBuffer = lpNew;
		m_nBufferSize = dwNewBufferSize;
	}
}

UINT QMemFile::read( void* lpBuf, UINT nCount )
{

	if (nCount == 0)
		return 0;

	Q_ASSERT(lpBuf != NULL);

	if (lpBuf == NULL) 
	{
		Q_ASSERT(0);
	}


	if (m_nPosition > m_nFileSize)
		return 0;

	UINT nRead;
	if (m_nPosition + nCount > m_nFileSize || m_nPosition + nCount < m_nPosition)
		nRead = (UINT)(m_nFileSize - m_nPosition);
	else
		nRead = nCount;

	QMemFile::memcpy((BYTE*)lpBuf, (BYTE*)m_lpBuffer + m_nPosition, nRead);
	m_nPosition += nRead;


	return nRead;
}

void QMemFile::write( const void* lpBuf, UINT nCount )
{

	if (nCount == 0)
		return;

	Q_ASSERT(lpBuf != NULL);

	if (lpBuf == NULL) 
	{
		Q_ASSERT(0);
	}
	//If we have no room for nCount, it must be an overflow
	if (m_nPosition + nCount < m_nPosition)
	{
		Q_ASSERT(0);
	}

	if (m_nPosition + nCount > m_nBufferSize)
		growfile(m_nPosition + nCount);

	Q_ASSERT(m_nPosition + nCount <= m_nBufferSize);

	QMemFile::memcpy((BYTE*)m_lpBuffer + m_nPosition, (BYTE*)lpBuf, nCount);

	m_nPosition += nCount;

	if (m_nPosition > m_nFileSize)
		m_nFileSize = m_nPosition;

}


void QMemFile::close()
{
	Q_ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0) || !m_bAutoDelete );
	Q_ASSERT(m_nFileSize <= m_nBufferSize);

	m_nGrowBytes = 0;
	m_nPosition = 0;
	m_nBufferSize = 0;
	m_nFileSize = 0;
	if (m_lpBuffer && m_bAutoDelete)
		freeMem(m_lpBuffer);
	m_lpBuffer = NULL;
}
